#include <stdio.h>

#include "../log.h"
#include "../memmap.h"
#include "mips.h"

char *registers[] = {
    "zr", "at", "v0", "v1", "a0", "a1", "a2", "a3",
    "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
    "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
    "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra"
};

char *fregisters[] = {
    "fpr0",  "fpr1",  "fpr2",  "fpr3",  "fpr4",  "fpr5",  "fpr6",  "fpr7",
    "fpr8",  "fpr9",  "fpr10", "fpr11", "fpr12", "fpr13", "fpr14", "fpr15",
    "fpr16", "fpr17", "fpr18", "fpr19", "fpr20", "fpr21", "fpr22", "fpr23",
    "fpr24", "fpr25", "fpr26", "fpr27", "fpr28", "fpr29", "fpr30", "fpr31"
};

char *cop0streg[] = {
    "st0 [Index]",
    "st1 [Random]",
    "st2 [EntryLo0]",
    "st3 [EntryLo1]",
    "st4 [Context]",
    "st5 [PageMask]",
    "st6 [Wired]",
    "st7 [?]",
    "st8 [BadVaddr]",
    "st9 [Count]",
    "st10 [EntryHi]",
    "st11 [Compare]",
    "st12 [SR]",
    "st13 [Cause]",
    "st14 [EPC]",
    "st15 [PRId]",
    "st16 [Config]",
    "st17 [LLAddr]",
    "st18 [WatchLO]",
    "st19 [WatchiHI]",
    "st20 [XContext]",
    "st21 [SCCode]",
    "st22 [CPUId]",
    "st23 [?]",
    "st24 [?]",
    "st25 [EBase]",
    "st26 [ECC]",
    "st27 [CacheErr]",
    "st28 [TagLo]",
    "st29 [TagHi]",
    "st30 [ErrorEPC]",
    "st31 [?]"
};

char *cop0ctlreg[] = {
    "ctl0 [COP0.EPC]",    
    "ctl1 [COP0.EPC.err]",
    "ctl2 [COP0.Status]",
    "ctl3 [COP0.Cause]",
    "ctl4 [GPR.v0]",
    "ctl5 [GPR.v1]",    
    "ctl6 [GPR.v0.err]",
    "ctl7 [GPR.v1.err]",
    "ctl8 [EXC_TABLE]",   
    "ctl9 [EXC_31_ERROR]", 
    "ctl10 [EXC_27_DEBUG]", 
    "ctl11 [EXC_8_SYSCALL]",
    "ctl12 [SC_TABLE]",
    "ctl13 [SC_MAX]",       
    "ctl14 [GPR.sp.Kernel]",
    "ctl15 [GPR.sp.User]",
    "ctl16 [CurrentTCB]",
    "ctl17 [?]",        
    "ctl18 [NMI_TABLE]",      
    "ctl19 [COP0.Status.err]",
    "ctl20 [COP0.Cause.err]",
    "ctl21 [?]",
    "ctl22 [?]",
    "ctl23 [?]",
    "ctl24 [?]",            
    "ctl25 [PROFILER_BASE]",
    "ctl26 [GPR.v0.dbg]",
    "ctl27 [GPR.v1.dbg]",
    "ctl28 [DBGENV]",
    "ctl29 [?]",
    "ctl30 [?]",
    "ctl31 [?]"
};

void cpu_reset()
{
    s32 i;
    for (i = 0; i < 32; i++)
    {
        cpu.r[i] = 0;
        cpu.f[i] = 0;
        cpu.cop0st[i] = 0;
        cpu.cop0ctl[i] = 0;
    }
    cpu.hi = 0;
    cpu.lo = 0;
    cpu.pc = 0;
    cpu.fcsr = 0;
}

void cpu_writeFCR(s32 reg, s32 value)
{
    _log(INF, CPU, "Writing FCR %d on reg %d", value, reg);
    if (reg == 31)
        cpu.fcsr = value;
    else
        _log(ERR, CPU, "Invalid FCR!");
}

s32 cpu_readFCR(s32 reg)
{
    _log(INF, CPU, "Reading FCR on reg %d", reg);
    if (reg == 31)
        return cpu.fcsr;
    else {
        _log(ERR, CPU, "Invalid FCR!");
        return 0;
    }
}

void cpu_setFcc(u8 value)
{
    cpu.fcsr = (cpu.fcsr & ~(1 << 23)) | (value << 23);
}

u8 cpu_getFcc()
{
    return (cpu.fcsr >> 23) & 1;
}

void cpu_showReg()
{
    s32 i;
    _log(INF, CPU, "---- Printing registers ----");
    _log(INF, CPU, "pc: 0x%08x", cpu.pc);
    _log(INF, CPU, "hi: 0x%08x", cpu.hi);
    _log(INF, CPU, "lo: 0x%08x", cpu.lo);
    for (i = 0; i < 32; i++)
        _log(INF, CPU, "%s: 0x%08x", registers[i], cpu.r[i]);
    _log(INF, CPU, "----------------------------");
}

CPUState cpu;

